# 10. 从输入url到页面加载完发生了什么?

# 流程

  1. DNS查询
  2. 浏览器发送请求
  3. 服务器处理请求并返回HTTP报文
  4. 浏览器接收响应
  5. 浏览器解析渲染页面
  6. 关闭TCP连接(http1.1默认是Connection: Keep-Alive所以不会关闭连接,http1.0默认是Connection: close响应后就会关闭连接,一般来说这个可有可无,一般在标签关闭时触发)

如果浏览器地址栏输入的是一个域名地址则进入流程,如果不是一个域名地址则进行默认搜索。

# 1. DNS查询

DNS解析的顺序为:

  • 浏览器缓存
  • 本地hosts文件
  • 系统缓存(运行内存中的缓存)
  • 路由器缓存
  • 根域名服务器查询

# 路由器缓存

有些路由器也有DNS缓存的功能,访问过的域名会存在路由器上。

# 根域名服务器查询

dns查询

递归过程:主机→本地DNS服务器→其他DNS服务器(如:我要找一个苹果吃,找到了A,问A有没有,A说我帮你去找B,B可能有,果真B有,然后B将苹果给了A,A再将苹果给我,这就是递归)。一路查下去中间不返回,得到最终结果才返回信息(浏览器到本地DNS服务器的过程)

迭代过程:本地DNS服务器→根服务器,本地DNS服务器→顶级域名服务器,本地DNS服务器→权限域名服务器;(如:我要找一个苹果,找到了A,A说我也没有,B可能有,你去找B吧;我又找B,B说我也没有,你去找C吧,我又去找C,终于找到了苹果,这就是迭代的过程)。就是本地DNS服务器到根域名服务器查询的方式

这里可能会发生DNS劫持。
DNS客户端和本地名称服务器是递归,而本地名称服务器和其他名称服务器之间是迭代。

# 2. 发送请求

# 涉及到的层级

  1. 应用层决定了向用户提供应用服务时通信的活动。
  2. 传输层提供处于网络连接中的两台计算机之间的数据传输。在传输层有两个性质不同的协议:TCP(传输控制协议)和UDP(用户数据报协议)。
  3. 网络层用来处理在网络上流动的数据包。
  4. 数据链路层用来处理连接网络的硬件部分。包括控制操作系统、硬件的设备驱动、NIC(网卡)、光纤等。

# 协议

HTTP协议:生成HTTP请求报文。
TCP协议:建立连接,销毁连接,分割数据。
IP协议:确认传输地址。

通信传输流

发送端从应用层往下走。发送端在层与层之间传输数据时,每经过一层时必定会被打上一个该层所属的首部信息。

# 应用层(HTTP协议)

首先作为发送端的客户端在应用层(HTTP协议)发出一个想看某个Web页面的请求。

# 传输层(TCP协议)

先进行三次握手连接。为了传输方便,在传输层(TCP协议)把应用层处收到的数据进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。

# 三次握手

三次握手用以同步客户端和服务端的序列号和确认号,并交换 TCP 窗口大小信息。

tcp连接

Ack:Acknowledge,告知已收到
Fin:Finally,结束会话
Seq:sequence,序列号
SYN:synchronize,同步; 表示开始会话请求

三次握手的本质是确认通信双方收发数据的能力

首先,我让信使运输一份信件给对方,对方收到了,那么他就知道了我的发件能力和他的收件能力是可以的。
于是他给我回信,我若收到了,我便知我的发件能力和他的收件能力是可以的,并且他的发件能力和我的收件能力是可以。
然而此时他还不知道他的发件能力和我的收件能力到底可不可以,于是我最后回馈一次,他若收到了,他便清楚了他的发件能力和我的收件能力是可以的。

# 网络层(IP协议)

在网络层(IP协议),增加作为通信目的地的MAC地址后转发给链路层。

# 链路层

连接客户端和服务器。

# 3. 服务器处理请求并返回HTTP报文

接收端则从链路层往上走(见2中的图)。接收端在层与层传输数据时,每经过一层时会把对应的首部消去。
接收端的服务器在链路层接收到数据,按顺序往上层发送,在传输层重组报文,一直到应用层。这时接收端接收到客户端发送的数据。

根据请求头和服务器配置处理请求后返回报文。

# 4. 浏览器接收响应

  • 根据响应头状态码做不同的事(比如重定向)
  • 对响应资源缓存(更新默认的请求头)

接下来根据MIME类型去解析响应内容。

# 5. 浏览器解析渲染页面

页面渲染

  • HTML代码转化成DOM
  • CSS代码转化成CSSOM(CSS Object Model)
  • 结合DOM和CSSOM,生成一棵渲染树(包含每个节点的视觉信息)
  • 生成布局(layout),即将所有渲染树的所有节点进行平面合成
  • 将布局绘制(paint)在屏幕上

# 渲染阻塞

当遇到一个script标签时,DOM 构建会被暂停,直至脚本完成执行,然后继续构建 DOM 树。

但如果 JS 依赖 CSS 样式,而CSS还没有被下载和构建时,JS样式就会计算错误。DOM树与CSSOM合并称为渲染树就会延迟,直至 CSS Rules 被构建。

所有我们知道:
CSS 会阻塞 DOM 渲染
JS 会阻塞后面的 DOM 解析

为了避免这种情况,应该以下原则:
CSS 资源排在 JavaScript 资源前面 JS 放在 HTML 最底部,也就是 前 另外,如果要改变阻塞模式,可以使用 defer 与 async

# 回流(reflow)与重绘(repaint)

回流(reflow)
当浏览器发现某个部分发现变化影响了布局时,需要倒回去重新渲染,会从html标签开始递归往下,重新计算位置和大小。
reflow基本是无法避免的,因为当你滑动一下鼠标、resize 窗口,页面就会产生变化。

重绘(repaint)
改变了某个元素的背景色、文字颜色等等不会影响周围元素的位置变化时,就会发生重绘。
每次重绘后,浏览器还需要合并渲染层并输出到屏幕上。

回流的成本要比重绘高很多,所以我们应该尽量避免产生回流。

display:none 会触发回流,而 visibility:hidden 只会触发重绘。

# js编译和执行

js编译执行

# 6. 关闭TCP连接

tcp四次挥手

  1. A——>B :A告诉B:“我发完了”;
  2. B——>A:B告诉A:“好的,我知道你发完了”
  3. B——>A:B告诉A:“我收完了”;
  4. A——>B:A告诉B:“好的,我知道你发收完了